

#include <string.h>
#include <iostream>
#include <ostream>
#include <fstream>
#include <iomanip>

#include "output.h"


using namespace std;


Output::Output(const int field_num, const string outfile)
:m_nFieldNum(field_num),m_strOutFile(outfile)
{

}

Output::Output(const Output &op)
:m_nFieldNum(op.m_nFieldNum), m_strOutFile(op.m_strOutFile)
{

}

Output& Output::operator=(const Output &op)
{
	if(&op == this)
		return *this;

	this->m_nFieldNum = op.m_nFieldNum;
	this->m_strOutFile = op.m_strOutFile;
	return *this;
}

void Output::FlushData2Stream(const DataSum &ds)
{
	if(m_strOutFile.empty())
	{
		DoIt(std::cout, ds);
	}
	else
	{
		ofstream fout(m_strOutFile.c_str());
		if(!fout)
		{
			cerr<<"open output file error"<<endl;
			return ;
		}
		DoIt(fout, ds);
		fout.close();
	}
}

void Output::DoIt(ostream &os, const DataSum &ds)
{
	const map<string, result_t*> &mp = ds.GetData();
	for(map<string, result_t*>::const_iterator iter = mp.begin();
		iter != mp.end();
		++iter)
	{
		os << setw(KeyWidth(ds.GetMaxKeyLength())) << iter->first << "\t";
		
		for(int i = 0; i < m_nFieldNum; ++i)
		{
			//os<< iter->second[i].retval;
			os << CalcValue(ds.GetCalcType(), iter->second[i]);
			if(i != m_nFieldNum -1)
				os << "\t";
		}
		os << std::endl;
	}
}

const double Output::CalcValue(const CALC_TYPE ct, const result_t &res) const
{
	if(ct == CALC_AVG)
	{
		if(0 == res.nflag)
			return res.retval;
		else
			return (double)(res.retval)/res.nflag;
	}
	return res.retval;
}

const int Output::KeyWidth(const int len) const
{
	int retval = ((len+1)/8)*8;
	return min(retval, 50);
}


///////////////////////////////////////////////////////////////////


HTMLOutput::HTMLOutput(const int field_num, const string outfile)
:Output(field_num, outfile)
{

}

HTMLOutput::HTMLOutput(const HTMLOutput &op)
:Output(op)
{

}

HTMLOutput& HTMLOutput::operator=(const HTMLOutput &op)
{
	if(&op == this)
		return *this;

	this->m_nFieldNum = op.m_nFieldNum;
	this->m_strOutFile = op.m_strOutFile;
	return *this;
}

void HTMLOutput::DoIt(ostream &os, const DataSum &ds)
{
	const map<string, result_t*> &mp = ds.GetData();

	os << "<table border=\"1\">" << endl;
	for(map<string, result_t*>::const_iterator iter = mp.begin();
		iter != mp.end();
		++iter)
	{
		os << "<tr>";

		os << "<td>"<<iter->first << "</td>";
		for(int i = 0; i < m_nFieldNum; ++i)
		{
			//os<< "<td>" << iter->second[i].retval << "</td>";
			os<< "<td>" << CalcValue(ds.GetCalcType(), iter->second[i]) << "</td>";
		}

		os << "</tr>";
		os << endl;
	}
	os << "</table>" << endl;
}




///////////////////////////////////////////////////////////////////


CSVOutput::CSVOutput(const int field_num, const string outfile)
:Output(field_num, outfile)
{

}

CSVOutput::CSVOutput(const CSVOutput &op)
:Output(op)
{

}

CSVOutput& CSVOutput::operator=(const CSVOutput &op)
{
	if(&op == this)
		return *this;

	this->m_nFieldNum = op.m_nFieldNum;
	this->m_strOutFile = op.m_strOutFile;
	return *this;
}

void CSVOutput::DoIt(ostream &os, const DataSum &ds)
{
	const map<string, result_t*> &mp = ds.GetData();

	for(map<string, result_t*>::const_iterator iter = mp.begin();
		iter != mp.end();
		++iter)
	{
		os << iter->first << ",";
		for(int i = 0; i < m_nFieldNum; ++i)
		{
			//os<< iter->second[i].retval;
			os << CalcValue(ds.GetCalcType(), iter->second[i]);
			if(i != m_nFieldNum - 1)
				os << ",";
		}

		os << endl;
	}
}




#ifdef TEST_OUTPUT

#include <iostream>


int main()
{
	map<string, long*> mp;
	long* pLong = new long[4];
	pLong[0] = 1000;
	pLong[1] = 2000;
	pLong[2] = 3000;
	pLong[3] = 4000;

	long* pLong2 = new long[4];
	memcpy(pLong2, pLong, sizeof(long)*4);

	mp["henry"] = pLong;
	mp["beijing"] = pLong2;

	Output *default_output = new Output(4);
	default_output->DoIt(std::cout, mp);
	Output *html_output = new HTMLOutput(4);
	html_output->DoIt(std::cout, mp);
	Output *csv_output = new CSVOutput(4);
	csv_output->DoIt(std::cout, mp);

	delete default_output;
	delete [] pLong;
	delete [] pLong2;

	return 0;
}

/*
Compile : g++ -g -o test_output -DTEST_OUTPUT output.cpp
*/
#endif



